Array.prototype.contains = function(obj) {
  var i = this.length;
  while (i--) {
    if (this[i] === obj) {
      return true;
    }
  }
  return false;
}

Raphael.fn.connection = function (obj1, obj2, line, bg) {
  
    if (obj1.line && obj1.from && obj1.to) {
        line = obj1;
        obj1 = line.from;
        obj2 = line.to;
    }
    var bb1 = obj1.getBBox();
    var bb2 = obj2.getBBox();
    var p = [{x: bb1.x + bb1.width / 2, y: bb1.y - 1},
        {x: bb1.x + bb1.width / 2, y: bb1.y + bb1.height + 1},
        {x: bb1.x - 1, y: bb1.y + bb1.height / 2},
        {x: bb1.x + bb1.width + 1, y: bb1.y + bb1.height / 2},
        {x: bb2.x + bb2.width / 2, y: bb2.y - 1},
        {x: bb2.x + bb2.width / 2, y: bb2.y + bb2.height + 1},
        {x: bb2.x - 1, y: bb2.y + bb2.height / 2},
        {x: bb2.x + bb2.width + 1, y: bb2.y + bb2.height / 2}];
    var d = {}, dis = [];
    for (var i = 0; i < 4; i++) {
        for (var j = 4; j < 8; j++) {
            var dx = Math.abs(p[i].x - p[j].x),
                dy = Math.abs(p[i].y - p[j].y);
            if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {
                dis.push(dx + dy);
                d[dis[dis.length - 1]] = [i, j];
            }
        }
    }
    if (dis.length == 0) {
        var res = [0, 4];
    } else {
        var res = d[Math.min.apply(Math, dis)];
    }
    var x1 = p[res[0]].x,
        y1 = p[res[0]].y,
        x4 = p[res[1]].x,
        y4 = p[res[1]].y,
        dx = Math.max(Math.abs(x1 - x4) / 2, 10),
        dy = Math.max(Math.abs(y1 - y4) / 2, 10),
        x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3),
        y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3),
        x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3),
        y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3);
    var path = ["M", x1.toFixed(3), y1.toFixed(3), "C", x2, y2, x3, y3, x4.toFixed(3), y4.toFixed(3)].join(",");
    if (line && line.line) {
        line.bg && line.bg.attr({path: path});
        line.line.attr({path: path});
    } else {
        var color = typeof line == "string" ? line : "#000";
        return {
            bg: bg && bg.split && this.path({stroke: bg.split("|")[0], fill: "none", "stroke-width": bg.split("|")[1] || 3}, path),
            line: this.path({stroke: color, fill: "none"}, path),
            from: obj1,
            to: obj2
        };
    }
};

function loadXMLDoc(dname)
{
  var xmlDoc;
  if (window.XMLHttpRequest)
    {
    xmlDoc=new window.XMLHttpRequest();
    xmlDoc.open("GET",dname,false);
    xmlDoc.send("");
    return xmlDoc.responseXML;
    }
  // IE 5 and IE 6
  else if (ActiveXObject("Microsoft.XMLDOM"))
    {
    xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc.async=false;
    xmlDoc.load(dname);
    return xmlDoc;
    }
  alert("Error loading document");
  return null;
}


Raphael.fn.getAnHost = function (hobj,i,len) {
//   zone=1;
  
  var rX=this.width; 
  var rY=this.height; 
  var width=(rX/7)-len/2;
  var height=(rY/4)-len/2;
  var offset = Math.floor(i/6); // in ogni sottocerchio ce ne stanno al massimo sei
  if(offset>1) { offset=offset/2; }
  var radius = 130+offset*100;
  var centreX=rX/2;
  var centreY=rY/2;
  var angle=Math.ceil(360/len+i)/Math.pow(2,offset);
  var X=centreX+Math.floor(radius*Math.cos(angle));
  
/*  var rand_no = Math.random();
  rand_no = rand_no * 100;*/
  
  if (X<0) X=width-10;
  if (X>rX) X=rX-width;    
  var Y=centreY+Math.floor(radius*Math.sin(angle));
  if (Y<0) Y=height-10;
  if (Y>rY) Y=rY-height;

  X=X-width/2;
  Y=Y-height/2;
  
  color="#A1ACAB";
  rect=this.rect(X,Y,width,height,10).attr({fill: color, stroke: color, "opacity": 0.7, "stroke-width": 1});

  var string='';
  
  
  for(var i=0; i<hobj.summary.length;i++) {
    string += hobj.summary[i] + '\n';
  }
  
  if(hobj.essid) {
    
    if(hobj.essid.length>20) { essidshort=hobj.essid.substring(0,13) + '..'; }
    else { essidshort=hobj.essid; }
    string+='essid:\n' + essidshort + '\n' }
  
  if(hobj.ip != null) { string+=hobj.ip + '\n' }
  else { string+=hobj.mac + '\n'}
  
  if(hobj.os!=null) { string+= hobj.os + "\n"; }
  
  string+="\n";
  if(hobj.ps!=null) { string += hobj.os; }

  for(var i=0; i<hobj.services.length;i++) {
    string += hobj.services[i] + '\n'; 
  }
 
  var c = this.image(hobj.image, X-25, Y-30, 50, 50);
  
  rect.node.style.cursor = "move";
  t = this.text(X+(1/2*width), Y+(1/2*height), string ).attr({"font": '12px "DeJaVu"', fill: "#000"});
 
  var components = this.set();
  components.push(rect);
  components.push(t);
  components.push(c);
  
  return components;
  
  
}



window.loadHosts = function () {
  
    var isDrag = false;
    var lasthostselected = false;
    var dragger = function (e) {
        this.dx = e.clientX;
        this.dy = e.clientY;
        isDrag = this;

	for (var mac in boxes) {
	  if(boxes[mac][0]==this) {
	    boxes[mac][1].hide();
	    boxes[mac][2].hide();
	    boxes[mac][0].attr({stroke: "black", "stroke-width": 5, "fill" : "#859BB2"});
	    
	    conn = connlst.getConnOf(mac);
	    
	    hostinfo(infos[mac]);
	    conninfo(conn,mac,infos[mac].gw);
	  }
	}

	if(lasthostselected!=this && lasthostselected!=false) {
	  lasthostselected.attr({stroke: 'none', "fill" : "#A1ACAB"});
	}
	lasthostselected=this;
	if(lastconnselected!=this && lastconnselected!=false) {
	  lastconnselected.animate({stroke: '#000', "stroke-width": 1},300);
	}
	lastconnselected=false;

    };
    
  connlst = new connlist();
  var connections = []; 
  boxes={};
  infos={};
  connections_hosts = [];
  
  xmlDoc=loadXMLDoc("out.xml");
  
  /*******************************************************/
  //  hosts fill
  
  var ifaceslist = xmlDoc.getElementsByTagName("IfaceMap");
  
  for (var i=0; i<ifaceslist.length; i++) {

    var iface = ifaceslist.item(i);
    var nodelist = xmlDoc.getElementsByTagName("Host");

    for (var j=0; j<nodelist.length; j++) {
    
      var node = nodelist.item(j);
      hinfo = new hostobj(node);
      
      var newbox = r.getAnHost(hinfo,j,nodelist.length);
      boxes[hinfo.mac] = newbox;
      infos[hinfo.mac] = hinfo;
      boxes[hinfo.mac][0].mousedown(dragger);
      
      if(hinfo.gw==true) {
	
	var pack = r.connection(globe, boxes[hinfo.mac][0], "#000", "#000|5");
	connections.push(pack);
	connections_hosts.push(["00:00:00:00:00:00", hinfo.mac]);
	  
      }
      
    }
  
};
    
document.onmousemove = function (e) {
    e = e || window.event;
    if (isDrag && e.clientX > 0 && e.clientX < r.width && e.clientY > 0 && e.clientY < r.height) {
	isDrag.translate(e.clientX - isDrag.dx, e.clientY - isDrag.dy);
//             isDrag.translate(0, e.clientY - isDrag.dy);
	for (var i = connections.length; i--;) {
	    r.connection(connections[i]);
	}
	for (var mac in boxes) {
    
	  if(boxes[mac][0]==isDrag) {
	    boxes[mac][1].translate(e.clientX - isDrag.dx, e.clientY - isDrag.dy);
	    boxes[mac][2].translate(e.clientX - isDrag.dx, e.clientY - isDrag.dy);
	  }
	}
    }

    r.safari();
    isDrag.dx = 0;
    isDrag.dx = e.clientX;
    isDrag.dy = e.clientY;

};
document.onmouseup = function (e) {
  
  if (isDrag) {
    
  for (var mac in boxes) {
      
    if(boxes[mac][0]==isDrag) {
	  
	  boxes[mac][0].toFront();
	
	  boxes[mac][1].show();
// 	      boxes[mac][1].attr({"opacity": 0});
	  boxes[mac][1].animate({"opacity": 1}, 200);
	  boxes[mac][1].toFront();
	
	  boxes[mac][2].show();
	  boxes[mac][2].attr({"opacity": 0});
	  boxes[mac][2].animate({"opacity": 1}, 300);
	  boxes[mac][2].toFront();
	
	}
      }
    }
    isDrag = false;
};
  

window.loadResolved = function() {
    utilsDoc=loadXMLDoc("utils.xml");
    resolvedHosts = [];
    /*******************************************************/
    //  ResolvedHosts fill
    
    for (var i=0; i<utilsDoc.getElementsByTagName("ResolvedHost").length; i++) {
      if(utilsDoc.getElementsByTagName("ResolvedHost")[i].getElementsByTagName("IP").length>0) {
	ip=utilsDoc.getElementsByTagName("ResolvedHost")[i].getElementsByTagName("IP")[0].childNodes[0].nodeValue; 
      }
      
      if(utilsDoc.getElementsByTagName("ResolvedHost")[i].getElementsByTagName("Host").length>0) {
	h=utilsDoc.getElementsByTagName("ResolvedHost")[i].getElementsByTagName("Host")[0].childNodes[0].nodeValue; 
      }
     resolvedHosts[ip]=h;
    }
}

window.loadConn = function() {
  
  
    lastconnselected = false;
    var dragger2 = function (e) {

	      this.attr({stroke: "#4D2500", "stroke-width": 5});

 	      for(var i=0; i<connections.length; i++) {
		if(connections[i].line==this) {
		  conn = connlst.getConnBetween(connections_hosts[i][0], connections_hosts[i][1]);
		  conninfo(conn);
		  clearhost();	
		}
	      }
	      
	      if(lastconnselected!=this && lastconnselected!=false) {
		lastconnselected.animate({stroke: '#000', "stroke-width": 1},300);
	      }
	      lastconnselected=this;
	      if(lasthostselected!=this && lasthostselected!=false) {
		lasthostselected.attr({stroke: 'none', "fill" : "#A1ACAB"});
	      }
	      lasthostselected=false;
	      
    };
    
  
       /*******************************************************/
      //  connections fill

      var nodelist = xmlDoc.getElementsByTagName("Connection");
      
      for (var j=0; j<nodelist.length; j++) {
	var thereIs = false;
	var node = nodelist.item(j);
	var state = node.getAttribute("Status");
	var service = node.getAttribute("ServiceName");
	
	conn = new connobj(node);
	connlst.add(conn);
	
	// aggiungo le linee delle connessioni
	if( (state=="OPENED" || state=="ACTIVE")) {
	  mac1 = conn.mac1;
	  mac2 = conn.mac2;
	  
	  for(var i =0; i<connections.length && boxes[mac1] && boxes[mac2]; i++) {
	    if( (connections[i].from==boxes[mac1][0] && connections[i].to==boxes[mac2][0]) || (connections[i].from==boxes[mac2][0] && connections[i].to==boxes[mac1][0])) { thereIs = true; } 
	  }
	  if(thereIs==false && boxes[mac1] && boxes[mac2]) {
	    var pack = r.connection(boxes[mac1][0], boxes[mac2][0], "#000");
	    pack.line.mouseover(dragger2);
	    connections.push(pack);
 	    //connection_hosts rimane, altrimenti non ho corrisponza tra le connessioni in connections (grafiche, poche)
	    //e le connessioni info in connlst (vere, molte) 
	    connections_hosts.push([mac1, mac2]);
	    
	    
	  }
	}
      }
      
    }
    
}


function reloadGraph() {

  if(r) r.remove();
  r = Raphael("holder", 800, 500);
  globe = r.image("images/internet.png", (r.width/2)-50, (r.height/2)-50, 100, 100);
  ethertext1 = r.text(150, 30, "etherSense" ).attr({"font": '50px "Verdana"', fill: "#000", opacity:.1});
  ethertext2 = r.text(80, 50, "beta version" ).attr({"font": '15px "Verdana"', fill: "#000", opacity:.5});

  loadHosts(); 
  loadConn();
  loadResolved();
  clearhost();
  clearconn();

  if(Object.size(infos)>0) {
    string="Loaded " + Object.size(infos) + " host";
    if(Object.size(infos)>1) string+="s";
    string+=" and " + Object.size(connections_hosts) + " connection";
    if(Object.size(connections_hosts)>1) string+="s";
    warn=0;
  }
  else {
    string="No host collected yet. Possible problems:<br/><ul>. Interface could be down. <br/>. Not enought informations captured.</ul>Try reloading in a few seconds."
    warn=1;
  }
  
  sendMsg(string,0,warn);

  
};


window.onload = function () {
    r=false;
    reloadGraph();
}